﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Drawing;
using System.IO;
using Icst.Leaflike.Util;
using Icst.Leaflike.Logging;

namespace Icst.Leaflike.Searching
{
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
    public class SearchService : ISearchService
    {
        const int COUNT = 10 * 1024;

        private int[] XX = new int[COUNT];
        private int[] YY = new int[COUNT];
        private int[] plants = new int[100];

        public Plant[] SearchPlants(Contour contour, int maxcount)
        {
            if (maxcount < 0 || maxcount > 10)
            {
                maxcount = 10;
                Logger.Warning("ALLOWED MAX COUNT IS 10");
            }

            //try
            //{
            //    Logger.Info("INIT SAFG");
            //    Logger.Info(AppConfig.SAFGcache);
            //    Logger.Info(AppConfig.SAFGclist);
            //    SAFGWrapper.Initialize(AppConfig.SAFGcache,AppConfig.SAFGclist);
            //}
            //catch (Exception e)
            //{
            //    Logger.Error("FAILED TO INIT SAFG. " + e.Message);
            //    throw new FaultException("FAILED TO INIT SAFG. " + e.Message);
            //}

            //SAFGWrapper.Initialize(AppConfig.SAFGcache, AppConfig.SAFGclist);

            int[] x = contour.Points.Select(p=>p.X).ToArray();
            int[] y = contour.Points.Select(p=>p.Y).ToArray();
            int length = Math.Min(x.Length,y.Length);

            Logger.Debug("CONTOUR LENGTH: " + length);

            int count = 0;
            for (int i = 0; i < plants.Length; ++i)
                plants[i] = 0;

            try
            {
                count = SAFGWrapper.LeafRgn(x, y, length, plants, maxcount);
                Logger.Debug("SEARCHED COUNT: " + count);
            }
            catch(Exception e)
            {
                Logger.Error("FAILED TO SEARCH PLANTS. "+e.Message);
                throw new FaultException("FAILED TO SEARCH PLANTS. " + e.Message);
            }

            count = Math.Min(count, maxcount);

            //no plant name??
            return plants.Take(count).Select(p => new Plant() { ID = p.ToString(), Name = "" }).ToArray();
        }

        public Contour[] SearchContours(byte[] bytes)
        {
            try
            {
                string fileName = Path.GetTempFileName();
                File.WriteAllBytes(fileName, bytes);
                try
                {
                    return GenerateContour(fileName);
                }
                finally
                {
                    File.Delete(fileName);
                }
            }
            catch (Exception e)
            {
                throw new FaultException(e.Message);
            }
        }

        public Contour[] SearchContoursByPath(string path)
        {
            return GenerateContour(path);
        }

        public Contour[] SearchContoursByUrl(string url)
        {
            //download
            byte[] bytes = NetUtilities.DownloadFile(url);
            if (bytes != null)
            {
                return SearchContours(bytes);
            }
            return new Contour[] { };
        }

        private Contour[] GenerateContour(string uploadPath)
        {
            Logger.Debug("GENERATING CONTOUR: " + uploadPath);

            List<ContourPoint> points = new List<ContourPoint>();

            int count = 0;
            try
            {
                for (int i = 0; i < XX.Length; ++i)
                    XX[i] = 0;
                for (int i = 0; i < YY.Length; ++i)
                    YY[i] = 0;

                count = SAFGWrapper.LeafContourByFile(uploadPath, XX, YY, COUNT);
                Logger.Debug("CONTOUR POINTS: " + count);

                for (int i = 0; i < count; ++i)
                {
                    points.Add(new ContourPoint(XX[i], YY[i]));
                }
            }
            catch (Exception e)
            {
                Logger.Error("FAILED TO GENERATE CONTOUR. " + e.Message);
                throw new FaultException(e.Message);
            }

            //no plant name??
            return new Contour[] { new Contour() { Points = points.ToArray() } };

            //string[] files = GetType().Assembly.GetManifestResourceNames()
            //    .Where(p => p.Contains(".cont"))
            //    .ToArray();
            //Random r = new Random((int)DateTime.Now.Ticks);
            //int s1 = r.Next(files.Length - 1);
            //int s2 = r.Next(files.Length - 1);
            //int s3 = r.Next(files.Length - 1);
            //int s4 = r.Next(files.Length - 1);

            //Dictionary<string, List<ContourPoint>> contours = new Dictionary<string, List<ContourPoint>>();
            //contours[Path.GetFileNameWithoutExtension(files[s1])] = ReadContourVec(files[s1]);
            //contours[Path.GetFileNameWithoutExtension(files[s2])] = ReadContourVec(files[s2]);
            //contours[Path.GetFileNameWithoutExtension(files[s3])] = ReadContourVec(files[s3]);
            //contours[Path.GetFileNameWithoutExtension(files[s4])] = ReadContourVec(files[s4]);

            //return contours.Select(p => new Contour() { Points = p.Value.ToArray() }).Take(3).ToArray();
        }
        private List<ContourPoint> ReadContourVec(string name)
        {
            List<ContourPoint> points = new List<ContourPoint>();
            using(Stream s = GetType().Assembly.GetManifestResourceStream(name))
            using (StreamReader reader = new StreamReader(s))
            {
                string line = reader.ReadLine();//ignore line 1
                line = reader.ReadLine();//ignore line 2
                line = reader.ReadLine();
                while (!string.IsNullOrEmpty(line))
                {
                    string[] splits = line.Split(' ');
                    if (splits.Length > 1)
                    {
                        int x = int.Parse(splits[0]);
                        int y = int.Parse(splits[1]);
                        points.Add(new ContourPoint(x, y));
                    }
                    line = reader.ReadLine();
                }
            }
            return points;
        }
    }
}
